package com.system.demo.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.system.demo.commonService.MailService;
import com.system.demo.commonService.RedisService;
import com.system.demo.entity.DTO.ForgetPassInfo;
import com.system.demo.entity.DTO.LoginInfo;
import com.system.demo.entity.DTO.UserInfoDTO;
import com.system.demo.entity.VO.UserVO;
import com.system.demo.entity.database.Admin;
import com.system.demo.entity.database.Student;
import com.system.demo.entity.database.User;
import com.system.demo.mapper.AdminMapper;
import com.system.demo.mapper.GraduationDateMapper;
import com.system.demo.mapper.StudentMapper;
import com.system.demo.mapper.UserMapper;
import com.system.demo.service.LoginService;
import com.system.demo.tool.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.mail.MessagingException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static cn.hutool.core.date.DateUtil.formatLocalDateTime;
import static com.system.demo.service.constant.MailConstant.FORGET_PASSWORD_SUBJECT;
import static com.system.demo.service.constant.MailConstant.FORGET_PASSWORD_TEMPLATE_PATH;
import static com.system.demo.utils.LoginUtils.generateCaptcha;
import static com.system.demo.utils.LoginUtils.generateCaptchaImage;

/**
 * 类描述: 有关登录的功能封装
 * @since 1.0
 * @author luodeng
 */
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private MailService mailService;
    @Autowired
    private StudentMapper studentMapper;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private GraduationDateMapper graduationDateMapper;
    /**
     * 对验证码生成图片
     *
     * @param loginInfo 前端提交的用户账号密码表单
     * @param token 验证码图片在redis中对应的key
     * @return 返回登录信息
     */
    public ResponseResult<?> login(LoginInfo loginInfo, String token) {

//        // 从Redis中获取验证码
//        String storedCaptcha = redisService.getKeyByToken("captcha:" + token);
//        if (storedCaptcha == null || !storedCaptcha.equalsIgnoreCase(loginInfo.getCaptcha())) {
//            return ResponseResult.BadRequest("验证码错误");
//        }
//        // 删除已使用的验证码
//        redisService.deleteTokenKey("captcha:" + token);
        try {

            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getUid, loginInfo.getUid());

            User existingUser = userMapper.selectOne(wrapper);

            if (existingUser == null) {
                return ResponseResult.Unauthorized("用户名或密码错误");
            }
            String encodePassword = DigestUtils.md5DigestAsHex(loginInfo.getPassword().getBytes());
            if (!existingUser.getPassword().equals(encodePassword)) {
                return ResponseResult.Unauthorized("用户名或密码错误");
            }

            //将uid保存
            String uid = existingUser.getUid();

            //进行毕业生筛选 毕业生不允许进入系统
            String yearPrefix = uid.substring(0, 2);
            // 查询数据库，获取对应年级的毕业日期
            LocalDate graduationDate = graduationDateMapper.getGraduationDateByPrefix(yearPrefix);
            if (graduationDate != null) {
                // 判断是否超过毕业日期
                LocalDate currentDate = LocalDate.now();
                if (currentDate.isAfter(graduationDate) || currentDate.equals(graduationDate)) {
                    return ResponseResult.Unauthorized("该年级毕业生无法登录，请联系管理员");
                }
            }

            //登录校验通过 现在处理前端返回值 如果是学生用户 or 有点权限的 副管理 只返回user以及student信息
            //如果是管理员登录 返回的是user+teacher表中的信息

            //此处得到的是该账号拥有的所有角色信息
            List<String> availableRolesByUid = userMapper.getAvailableRolesByUid(existingUser.getUid());
            if (availableRolesByUid.contains("ROLE_STUDENT")){
                //这里处理 以上所说的第一条 返回user以及student信息
                LambdaQueryWrapper<Student> studentWrapper = new LambdaQueryWrapper<>();
                studentWrapper.eq(Student::getUid, uid);
                Student student = studentMapper.selectOne(studentWrapper);

                List<String> menuListByUserId = userMapper.getMenuValuesByUid(uid);

                StpUtil.login(loginInfo.getUid());

                UserInfoDTO userInfoDTO = new UserInfoDTO();
                userInfoDTO.setUid(student.getUid());
                userInfoDTO.setSatoken(StpUtil.getTokenValue());
                userInfoDTO.setUsername(existingUser.getUsername());
                userInfoDTO.setSystemMenus(menuListByUserId);
                userInfoDTO.setUserVO(new UserVO(student.getStudentName(), student.getStudentGender(), student.getStudentClass()));
                userInfoDTO.setUserRole(availableRolesByUid);
                userInfoDTO.setAvatar(existingUser.getAvatar());
                userInfoDTO.setLastLoginTime(formatLocalDateTime(existingUser.getLastLoginTime()));

                if(existingUser.getLastLoginTime() != null){
                    //唯一更新loginTime的地方 必须要有time才能更新time  没有time就得去改密码接口获取time
                    existingUser.setLastLoginTime(LocalDateTime.now());
                    userMapper.updateById(existingUser);
                }
                return ResponseResult.success("登录成功", userInfoDTO);

            }
            if(availableRolesByUid.contains("ROLE_ADMIN")){
                //这里处理以上所说的第二条 返回 user+teacher 信息
                LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(Admin::getUid, uid);

                StpUtil.login(loginInfo.getUid());

                Admin admin = adminMapper.selectOne(queryWrapper);
                List<String> menuListByUserId = userMapper.getMenuValuesByUid(uid);

                UserInfoDTO userInfoDTO = new UserInfoDTO();
                userInfoDTO.setUid(admin.getUid());
                userInfoDTO.setSatoken(StpUtil.getTokenValue());
                userInfoDTO.setSystemMenus(menuListByUserId);
                userInfoDTO.setUsername(existingUser.getUsername());
                userInfoDTO.setUserRole(availableRolesByUid);
                userInfoDTO.setUserVO(new UserVO(admin.getAdminName(), admin.getAdminGender(),admin.getAdminDep()));
                userInfoDTO.setAvatar(existingUser.getAvatar());
                userInfoDTO.setLastLoginTime(formatLocalDateTime((existingUser.getLastLoginTime())));

                if(existingUser.getLastLoginTime() != null){
                    //唯一更新loginTime的地方 必须要有time才能更新time  没有time就得去改密码接口获取time
                    existingUser.setLastLoginTime(LocalDateTime.now());
                    userMapper.updateById(existingUser);
                }
                return ResponseResult.success("登录成功", userInfoDTO);
            }
            return ResponseResult.Unauthorized("未知角色，请联系管理员");

        }catch (NumberFormatException e){
            return ResponseResult.InternalServerError("服务器内部错误" + e.getMessage());
        }
    }

    /**
     * 对指定邮箱发送找回密码邮件
     *
     * @param emailReceiver 用户邮箱
     * @return 返回信息
     */
    @Override
    public ResponseResult<Map<String, Object>> sendMail(String emailReceiver) throws MessagingException {
        // 检查邮箱是否绑定用户
        String emailByMail = userMapper.findEmailByMail(emailReceiver);
        if (emailByMail == null) {
            return ResponseResult.NotFound("该邮箱未绑定任何用户");
        }

        // 生成6位随机验证码，存入 List<Integer>
        List<Integer> code = new Random().ints(6, 0, 10)
                .boxed()
                .collect(Collectors.toList());
        // 将验证码转换为字符串
        String codeString = code.stream()
                .map(String::valueOf)
                .collect(Collectors.joining());

        // 发送邮件
        boolean isMailSent = mailService.sendMail(emailReceiver,
                FORGET_PASSWORD_SUBJECT,
                FORGET_PASSWORD_TEMPLATE_PATH,
                Collections.singletonMap("verifyCode", code));

        if (!isMailSent) {
            return ResponseResult.InternalServerError("邮件发送失败，请稍后重试");
        }

        // 生成唯一标识并存储到 Redis
        String token = UUID.randomUUID().toString();
        try {
            redisService.setTokenKey("mailCode:" + token, codeString, 5, TimeUnit.MINUTES);
        } catch (Exception e) {
            return ResponseResult.InternalServerError("服务器内部错误，请稍后重试");
        }
        Map<String, Object> response = new HashMap<>();
        response.put("mailToken", token);

        return ResponseResult.success("邮件发送成功", response);
    }



    /**
     * 找回密码 验证code
     *
     * @param forgetPassInfo 前端提交的新密码以及code表单
     * @param token code对应存在redis中的key
     * @return 返回信息
     */
    @Override
    public ResponseResult<Map<String, Object>> forgetPass(ForgetPassInfo forgetPassInfo, String token) {

        // 从 Redis 中获取验证码
        String savedMailCode = redisService.getKeyByToken("mailCode:" + token);
        if (savedMailCode == null) {
            return ResponseResult.Unauthorized("验证码无效或已过期");
        }
        System.out.println(savedMailCode);
        System.out.println(forgetPassInfo.getMailCode());
        if(!savedMailCode.equals(forgetPassInfo.getMailCode())){
            return ResponseResult.Unauthorized("验证码错误");
        }

        // 查询用户
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUid, forgetPassInfo.getUid())
                .eq(User::getMail, forgetPassInfo.getMail());

        User user = userMapper.selectOne(wrapper);

        if (user == null) {
            return ResponseResult.NotFound("请检查当前账号、邮箱是否匹配");
        }

        user.setPassword(DigestUtils.md5DigestAsHex(forgetPassInfo.getNewPassword().getBytes()));
        userMapper.updateById(user);

        // 删除已使用的验证码
        redisService.deleteTokenKey("mailCode:" + token);

        return ResponseResult.success("修改密码成功");
    }

    @Override
    public ResponseResult<?> logout() {
        StpUtil.logout();
        return ResponseResult.success("退出成功");
    }


    /**
     * 验证码生成以及redis缓存
     *
     * @return 返回验证码图片
     */
    @Override
    public ResponseResult<Map<String, Object>> getCaptcha() {
        // 生成唯一Token
        String token = UUID.randomUUID().toString();
        // 生成验证码
        String captchaCode = generateCaptcha();
        // 将验证码存储到Redis中，设置过期时间为5分钟
        redisService.setTokenKey("captcha:" + token, captchaCode, 5, TimeUnit.MINUTES);
        // 生成验证码图片
        byte[] imageBytes = generateCaptchaImage(captchaCode);
        // 返回Token和验证码图片
        Map<String, Object> response = new HashMap<>();
        response.put("token", token);
        response.put("image", "data:image/png;base64," + Base64.getEncoder().encodeToString(imageBytes));
        return ResponseResult.success("验证码生成成功",response);
    }


}
